/*
 * UDPPinger.cpp
 *
 *  Created on: 24.10.2011
 *      Author: niea
 */

#include <iostream>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>

#include "constants.h"
#include "UDPPinger.h"

UDPPinger::UDPPinger() {

}

UDPPinger::~UDPPinger() {

}

int UDPPinger::ping(int port) const {
	int fdsocket = socket(AF_INET, SOCK_DGRAM, 0);
	if (fdsocket < 0) {
		std::cerr << "UDP Socket error: socket" << std::endl;
		return C_ERROR;
	}

	fcntl(fdsocket, F_SETFL, O_NONBLOCK);

	int opt_true = 1;
	setsockopt(fdsocket, SOL_SOCKET, SO_BROADCAST, &opt_true, sizeof(opt_true));

	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);

	char msg[CONST_BUFFER_SIZE] = "hello";
	if (sendto(fdsocket, msg, sizeof(msg), 0, (sockaddr*) &addr, sizeof(addr))
			< 0) {
		std::cerr << "UDP Socket error: sendto" << std::endl;
		return C_ERROR;
	}

	timeval timeout;
	timeout.tv_sec = 0;
	timeout.tv_usec = CONST_TIMEOUT * 1000;

	fd_set readset;
	FD_ZERO(&readset);
	FD_SET(fdsocket, &readset);

	int servers_count = 0;
	while (1) {
		if (select(fdsocket + 1, &readset, NULL, NULL, &timeout) <= 0) {
			if (servers_count == 0) {
				std::cout << "No servers found" << std::endl;
			}
			return C_OK;
		} else {

			socklen_t length = sizeof(addr);
			if (recvfrom(fdsocket, msg, sizeof(msg), 0, (sockaddr*) &addr,
					&length) < 0) {
				std::cerr << "UDP Socket error: recfrom" << std::endl;
				return C_ERROR;
			}

			servers_count++;
			char *ip;
			ip = inet_ntoa(addr.sin_addr);
			char *n_pos = strstr(msg, "\n");
			if (n_pos){
				*n_pos = ' ';
			}
			std::cout << "<" << ip << "> " << msg << std::endl;
		}
	}
	return C_OK;
}
